/////////////////////////////////////////////////////////////////////////////
// Data structures  
/////////////////////////////////////////////////////////////////////////////

#ifndef _STRUCTURES_H_
#define _STRUCTURES_H_

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include "SCSystem.hpp"
#include "Point2D.hpp"
#include "Point3D.hpp"
#include "Vector3D.hpp"
#include <vector>
#include <utility>
#include <gl/gl.h>

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace SC {

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/// RGB Colour structure
typedef struct Colour {

	/// Default constructor
	Colour()
	: r(0.f), g(0.f), b(0.f)
	{}

	/// Creates a colour from given values
	Colour(const float r, const float g, const float b)
	: r(r), g(g), b(b)
	{}

	/// Creates a copy of the given instance
	Colour(const Colour & inst)
	: r(inst.r), g(inst.g), b(inst.b)
	{}

	/// Affectation operator
	Colour & operator = (const Colour & inst) {
		if (this != &inst) {
			this->r = inst.r;
			this->g = inst.g;
			this->b = inst.b;
		}
		return *this;
	}

	/// RGB components
	float r, g, b;

};

/// RGBA Colour structure
typedef struct ColourRGBA {

	/// Default constructor
	ColourRGBA()
	: r(0.f), g(0.f), b(0.f), a(1.f)
	{}

	/// Creates a copy of the given instance
	ColourRGBA(const ColourRGBA & inst)
	: r(inst.r), g(inst.g), b(inst.b), a(inst.a)
	{}

	/// Affectation operator
	ColourRGBA & operator = (const ColourRGBA & inst) {
		if (this != &inst) {
			this->r = inst.r;
			this->g = inst.g;
			this->b = inst.b;
			this->a = inst.a;
		}
		return *this;
	}

	/// Creates a copy of the given instance
	ColourRGBA(const Colour & inst)
	: r(inst.r), g(inst.g), b(inst.b), a(1.f)
	{}

	/// Affectation operator
	ColourRGBA & operator = (const Colour & inst) {
		this->r = inst.r;
		this->g = inst.g;
		this->b = inst.b;
		this->a = 1.f;
		return *this;
	}

	/// RGBA components
	float r, g, b, a;

};

/// Graph system node data
class SystemNodeData {

	public:

		/// Default constructor
		SystemNodeData()
		: system(NULL) {}

		/// Constructor
		SystemNodeData(
			const SC::SCSystem & system
		) : system(&system) {}

		/// Creates a copy of the given instance
		SystemNodeData(const SystemNodeData & inst)
		:	system(inst.system), sub_body_idx(inst.sub_body_idx),
			struct_location(inst.struct_location), struct_velocity(inst.struct_velocity),
			struct_mass(inst.struct_mass), usage(inst.usage), changes(inst.changes)
		{}

		/// Affectation operator
		SystemNodeData & operator = (const SystemNodeData & inst) {
			if (this != &inst) {
				this->system = inst.system;
				this->sub_body_idx = inst.sub_body_idx;
				this->struct_location = inst.struct_location;
				this->struct_velocity = inst.struct_velocity;
				this->struct_mass = inst.struct_mass;
				this->usage = inst.usage;
				this->changes = inst.changes;
			}
			return *this;
		}

		/// System
		const SC::SCSystem * system;

		/// Sub-systems bodies index (for the explorer)
		std::vector<unsigned int> sub_body_idx;

		/// Location (for the structure)
		Types::Point3D<float> struct_location;

		/// Velocity (for the structure)
		Types::Vector3D<float> struct_velocity;

		/// Mass (for the structure)
		float struct_mass;

		/// Usage (for the structure)
		float usage;

		/// Stored changes
		std::vector< std::pair<unsigned int, int> > changes;

};

/// Graph system arc data
class SystemArcData {

	public:

		/// Default constructor
		SystemArcData()
		: struct_optimum(1.f), struct_strength(1.f) {}

		/// Creates a copy of the given instance
		SystemArcData(const SystemArcData & inst)
		: struct_optimum(inst.struct_optimum), struct_strength(inst.struct_strength)
		{}

		/// Affectation operator
		SystemArcData & operator = (const SystemArcData & inst) {
			if (this != &inst) {
				this->struct_optimum = inst.struct_optimum;
				this->struct_strength = inst.struct_strength;
			}
			return *this;
		}

		/// Optimum length (for the structure)
		float struct_optimum;

		/// Spring strength (for the structure)
		float struct_strength;

};

// Node data type
#define NData Types::NodeData<wxString,wxColour,SystemNodeData,wxRect>
// Arc data type
#define AData Types::ArcData<wxString,wxColour,SystemArcData>

/// Body data structure for the explorer
typedef struct BodyData {

	/// Constructor
	BodyData(const int node_idx = -1)
	: node_idx(node_idx), blinking(0.f), blink(false)
	{}

	/// Creates a copy of the given instance
	BodyData(const BodyData & inst)
	:	node_idx(inst.node_idx), links(inst.links),
		blinking(inst.blinking), blink(inst.blink)
	{}

	/// Affectation operator
	BodyData & operator = (const BodyData & inst) {
		if (this != &inst) {
			this->node_idx = inst.node_idx;
			this->links = inst.links;
			this->blinking = inst.blinking;
			this->blink = inst.blink;
		}
		return *this;
	}

	/// Node index
	int node_idx;

	/// Interaction links (body index, age)
	std::vector< std::pair<unsigned int, float> > links;

	/// Blinking time
	float blinking;

	/// Blinking state
	bool blink;

};

// Location engine body types
#define LEB_P double
#define LEB_D BodyData

// Define the scope body index
#define SCOPE_BODY_IDX 0xFFFFFFFF

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
